package com.apache.rpc.common;

import com.apache.exception.BusinessException;
import com.apache.rpc.entity.Protocol;
import net.sf.json.JSONArray;
import net.sf.json.xml.XMLSerializer;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.*;

public class XMLMapParse {

    private Logger log = LoggerFactory.getLogger(XMLMapParse.class);

    private static XMLMapParse instance;

    private XMLMapParse() {
    }

    public static XMLMapParse instance() {
        if (null == instance) {
            instance = new XMLMapParse();
        }
        return (instance);
    }

    /**
     * TODO 生成xml的报文
     */
    public String buildSingleXML(Protocol protocol) {

        try {
            Element root = builderHeaderInfo(protocol.getReqFlag(), protocol.getBeanId(),
                    protocol.getRespType(), protocol.getIsClose(),
                    getDefaultStr(protocol.getProtocolType(), "socket"));

            Element body = new Element("Body"); // 生成元素：Body

            addElementToBody(body, protocol.getParams());
            root.addContent(body);
            return elementToString(root);

        } catch (Exception e) {
            log.info("构造交易报文出现错误:reqFlag=" + protocol.getReqFlag() + ",BeanId=" + protocol
                    .getBeanId(), e);
        }
        return "";

    }

    /**
     * 函数名称： xmlGetData 函数功能： 解析后台返回的xml报文,将结果保存在ArrayList数组 参数说明：
     *
     * @param xmldata: xml字符串。
     */
    @SuppressWarnings("rawtypes")
    public void xmlGetData(String xmldata, Map<String, Object> headMap,
            Map<String, Object> bodyMap) {
        try {
            xmldata = xmldata.trim();
            SAXBuilder builder = new SAXBuilder();
            Reader in_xml = new StringReader(xmldata);
            Document doc = builder.build(in_xml);// "c:\\xml\\getxml_doc.xml"
            if (null == doc) {
                log.info("报文解析错误,报文内容为空");
                throw new BusinessException("报文内容为空");
            }
            Element e0 = doc.getRootElement();
            if (null == e0) {
                log.info("报文解析错误,报文内容为空");
                throw new BusinessException("报文内容为空");
            }
            List list1 = e0.getChildren("Head");
            List list2 = e0.getChildren("Body");// Root-->Body 获得指定名称子元素的List
            if (list1 == null || list2 == null) {
                log.info("报文解析错误,报文格式不符合规范");
                throw new BusinessException("报文格式不符合规范");
            }
            // 在head里边查找xmlTagName
            if (list1 != null) {
                Element e_txf = (Element) list1.get(0);
                if (!isNull(e_txf.getChildText("MethodCode"))) {
                    headMap.put("MethodCode", e_txf.getChildText("MethodCode"));
                }
                if (!isNull(e_txf.getChildText("BeanId"))) {
                    headMap.put("BeanId", e_txf.getChildText("BeanId"));
                }
                if (!isNull(e_txf.getChildText("ParamType"))) {
                    headMap.put("ParamType", e_txf.getChildText("ParamType"));
                }
                if (!isNull(e_txf.getChildText("SocketClose"))) {
                    headMap.put("SocketClose", e_txf.getChildText("SocketClose"));
                }
            }

            if (list2 != null) {
                Element e_rmsg = (Element) list2.get(0);// 获得Body元素,假如Root下有多个Body，我们只取第一个Body.
                List list3 = e_rmsg.getChildren();
                if (!isEmpty(list3)) {
                    int count = list3.size();
                    for (int i = 0; i < count; i++) {
                        Element elt = (Element) list3.get(i);
                        if (!isEmpty(elt.getChildren())) {
                            bodyMap.put(elt.getName(), xmlToJavaBean(elt.getChildren()));
                        } else {
                            bodyMap.put(elt.getName(), elt.getText());
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.info("解析应答报文出现错误", e);
            log.info("socket erver xml:" + xmldata);
        }
    }

    public String jsonToXMl(String json) {
        XMLSerializer xmlSerializer = new XMLSerializer();
        String str = xmlSerializer.write(JSONArray.fromObject(json)).toString();
        str = str.replaceAll("<a>", "<xml-body>");
        str = str.replaceAll("</a>", "</xml-body>");
        str = str.replaceAll("</e>", "");
        str = str.replaceAll(" type=\"string\"", "");
        str = str.replaceAll(" class=\"object\"", "");
        int dd = str.indexOf("<xml-body>");
        str = str.substring(0, dd + 10) + str.substring(dd + 13);
        return str;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private List xmlToJavaBean(List list) {
        List result = new ArrayList();
        int count = list.size();
        for (int i = 0; i < count; i++) {
            Element elt = (Element) list.get(i);
            if ("list".equals(elt.getName())) {
                List list3 = elt.getChildren();
                if (isEmpty(list3)) {
                    result.add(elt.getText());
                } else {
                    for (int j = 0; j < list3.size(); j++) {
                        Element elt2 = (Element) list3.get(j);
                        result.add(elt2.getText());
                    }
                }
            } else {
                Map<String, String> map = new HashMap<String, String>();
                List list3 = elt.getChildren();
                if (isEmpty(list3)) {
                    map.put(elt.getName(), elt.getText());
                } else {
                    for (int j = 0; j < list3.size(); j++) {
                        Element elt2 = (Element) list3.get(j);
                        map.put(elt2.getName(), elt2.getText());
                    }
                }
                result.add(map);
            }
        }
        return result;
    }

    /**
     * 函数名称： xmlGetData 函数功能： 解析后台返回的xml报文,将结果保存在ArrayList数组 参数说明：
     *
     * @param xmldata: xml字符串。
     */
    @SuppressWarnings("rawtypes")
    public void xmlGetDataToHead(String xmldata, Map<String, Object> headMap) {
        try {
            xmldata = xmldata.trim();
            SAXBuilder builder = new SAXBuilder();
            Reader in_xml = new StringReader(xmldata);
            Document doc = builder.build(in_xml);// "c:\\xml\\getxml_doc.xml"
            Element e0 = doc.getRootElement();
            if (doc == null || e0 == null) {
                log.info("报文解析错误,报文内容为空");
                throw new BusinessException("报文内容为空");
            }
            List list1 = e0.getChildren("Head");
            if (list1 == null) {
                log.info("报文解析错误,报文格式不符合规范");
                throw new BusinessException("报文格式不符合规范");
            }
            // 在head里边查找xmlTagName
            if (list1 != null) {
                Element e_txf = (Element) list1.get(0);
                if (!isNull(e_txf.getChildText("MethodCode"))) {
                    headMap.put("MethodCode", e_txf.getChildText("MethodCode"));
                }
                if (!isNull(e_txf.getChildText("BeanId"))) {
                    headMap.put("BeanId", e_txf.getChildText("BeanId"));
                }
                if (!isNull(e_txf.getChildText("ParamType"))) {
                    headMap.put("ParamType", e_txf.getChildText("ParamType"));
                }
                if (!isNull(e_txf.getChildText("SocketClose"))) {
                    headMap.put("SocketClose", e_txf.getChildText("SocketClose"));
                }
                if (!isNull(e_txf.getChildText("ProtocolType"))) {
                    headMap.put("ProtocolType", e_txf.getChildText("ProtocolType"));
                } else {
                    headMap.put("ProtocolType", "socket");
                }

            }
        } catch (Exception e) {
            log.info("解析应答报文出现错误", e);
        }
    }

    private Element builderHeaderInfo(String methodCode, String beanId, String paramtype,
            String isClose, String protocolType) {
        Element root, head;
        Element hVersion, hPCode, hParamType, hBeanId, hSocketCLose, protocolTypee;

        root = new Element("xml-body"); // 生成根元素：Root
        head = new Element("Head"); // 生成元素：Head

        hVersion = new Element("Version");
        hPCode = new Element("MethodCode");
        hBeanId = new Element("BeanId");
        hParamType = new Element("ParamType");
        protocolTypee = new Element("ProtocolType");
        hSocketCLose = new Element("SocketClose");

        hVersion.setText("1.0");
        hPCode.setText(methodCode);
        hBeanId.setText(beanId);
        hParamType.setText(paramtype);
        hSocketCLose.setText(isClose);
        protocolTypee.setText(protocolType);

        head.addContent(hVersion);
        head.addContent(hPCode);
        head.addContent(hBeanId);
        head.addContent(hParamType);
        head.addContent(hSocketCLose);
        head.addContent(protocolTypee);
        root.addContent(head);
        return root;
    }

    private String elementToString(Element root)
            throws BusinessException, FileNotFoundException, IOException {
        Document doc = new Document(root);
        String xmlfilename;
        Format format = Format.getRawFormat();
        format.setEncoding("UTF-8"); // 设置xml文件的字符为gb2312
        format.setIndent("    "); // 设置xml文件的缩进为4个空格
        XMLOutputter XMLOut = new XMLOutputter(format);// 元素后换行一层元素缩四格
        xmlfilename = XMLOut.outputString(doc);
        //xmlfilename = xmlfilename.replaceAll("encoding=\"UTF-8\"", "encoding=\"UTF-8\"");
        return xmlfilename;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void addElementToBody(Element eBody, Map<String, Object> tranMap) throws Exception {
        Element element_tmp;
        for (String key : tranMap.keySet()) {
            if (!isNull(key) && !isEmpty(tranMap.get(key))) {
                element_tmp = new Element(key);
                String keyValueClass = tranMap.get(key).getClass().getSimpleName();
                if ("ArrayList".equals(keyValueClass) || "List".equals(keyValueClass)) {
                    String valueClass = ((List) tranMap.get(key)).get(0).getClass().getSimpleName();
                    if ("String".equals(valueClass)) {
                        addElementsToBodyList(element_tmp, (List) tranMap.get(key));
                    } else {
                        addElementsToBody(element_tmp, (List) tranMap.get(key));
                    }
                } else if ("Map".equalsIgnoreCase(keyValueClass) || "HashMap"
                        .equalsIgnoreCase(keyValueClass)) {
                    addElementsToBodyMap(element_tmp, (Map) tranMap.get(key));
                } else {
                    String keyValue = String.valueOf(tranMap.get(key));
                    element_tmp.setText(keyValue);
                }
                eBody.addContent(element_tmp);
            } else {
                continue;
            }
        }
    }

    private void addElementsToBodyMap(Element eBody, Map<String, List<String>> tranList) {
        if (!isEmpty(tranList)) {
            Element element_tmp;
            for (String key : tranList.keySet()) {
                List<String> tranMap = tranList.get(key);
                if (!isEmpty(tranMap)) {//list数据
                    Element map_tmp = new Element("list");
                    for (String keyStr : tranMap) {
                        if (!isNull(key)) {
                            element_tmp = new Element("String");
                            element_tmp.setText(keyStr);
                            map_tmp.addContent(element_tmp);
                        } else {
                            log.info("body字段名称错误:空字串");
                            throw new BusinessException("body字段名称错误:空字串");
                        }
                    }
                    eBody.addContent(map_tmp);
                } else {//map数据
                    String keyValueClass = tranList.get(key).getClass().getSimpleName();
                    if ("Map".equalsIgnoreCase(keyValueClass) || "HashMap"
                            .equalsIgnoreCase(keyValueClass)) {
                        Element map_tmp = new Element("map");
                        Map<String, Object> tranMap2 = (Map<String, Object>) tranList.get(key);
                        for (String key2 : tranMap2.keySet()) {
                            if (!isNull(key2)) {
                                element_tmp = new Element(key2);
                                String keyValue = String.valueOf(tranMap2.get(key2));
                                element_tmp.setText(keyValue);
                                map_tmp.addContent(element_tmp);
                            } else {
                                log.info("body字段名称错误:空字串");
                            }
                        }
                        eBody.addContent(map_tmp);
                    }
                }
            }
        }
    }

    private void addElementsToBody(Element eBody, List<Map<String, Object>> tranList) {
        if (!isEmpty(tranList)) {
            int count = tranList.size();
            for (int i = 0; i < count; i++) {
                Element element_tmp;
                Element map_tmp = new Element("map");
                Map<String, Object> tranMap = tranList.get(i);
                for (String key : tranMap.keySet()) {
                    if (!isNull(key)) {
                        element_tmp = new Element(key);
                        String keyValue = String.valueOf(tranMap.get(key));
                        element_tmp.setText(keyValue);
                        map_tmp.addContent(element_tmp);
                    } else {
                        log.info("body字段名称错误:空字串");
                        throw new BusinessException("body字段名称错误:空字串");
                    }
                }
                eBody.addContent(map_tmp);
            }
        }
    }

    private void addElementsToBodyList(Element eBody, List<String> tranList) {
        if (!isEmpty(tranList)) {
            Element map_tmp = new Element("list");
            for (String key : tranList) {
                if (!isNull(key)) {
                    Element element_tmps = new Element("String");
                    element_tmps.setText(key);
                    map_tmp.addContent(element_tmps);
                } else {
                    log.info("body字段名称错误:空字串");
                    throw new BusinessException("body字段名称错误:空字串");
                }
            }
            eBody.addContent(map_tmp);
        }
    }

    /**
     * 判断对象数组是否为空
     *
     * @param object 对象数组
     * @return 如果object为空返回true，不为空返回false
     */
    public boolean isNull(Object[] object) {
        if (object == null || object.length == 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断一个字符串是否为空
     *
     * @param str 传入的字符串
     * @return 如果str为空返回true，不为空返回false
     */
    public boolean isNull(String str) {
        if (str == null) {
            return true;
        }
        str = str.trim();
        if ((str.equals("null")) || (str.equals(""))) {
            return true;
        }
        return false;
    }

    /**
     * 判断对象是否为空
     *
     * @param obj 传入的对象
     * @return 如果obj为空返回true，不为空返回false
     */
    public boolean isEmpty(Object obj) {
        return obj == null;
    }

    /**
     * 判断一个list集合是否为空
     *
     * @param list 传入的list
     * @return 如果list为空或者长度为0返回true，不为空返回false
     */
    public boolean isEmpty(List list) { //
        return list == null || list.size() == 0;
    }

    private String getDefaultStr(String text, String defaultStr) {
        if (isNull(text))
            return defaultStr;
        return text;
    }

    /**
     * 判断一个list集合是否为空
     *
     * @param collection 传入的集合
     * @return 如果collection为空或者长度为0返回true，不为空返回false
     */
    private boolean isEmpty(Collection collection) { //
        return collection == null || collection.isEmpty();
    }

    public static void main(String[] args) {
        //		String json2 = "<?xml version='1.0' encoding='UTF-8'?><xml-body><Head><Version>1.0</Version><MethodCode>getDealmakingData</MethodCode><BeanId>dealmakingService</BeanId><ParamType>XML</ParamType></Head><Body><tradeId>E0000001243</tradeId><prodId>P0031</prodId></Body></xml-body>";
        //		String json = "[{\"Head\":{\"MethodCode\":\"getDealmakingData\",\"BeanId\":\"dealmakingService\",\"ParamType\":\"json\"},\"Body\":{\"tradeId\":\"E0000001243\",\"prodId\":\"P0031\",\"prodId2\":\"P0031\"}}]";
        //		if (!json2.startsWith("<?xml "))
        //			System.out.println(json2);
        //		else {
        //			System.out.println(XMLMapParse.instance().jsonToXMl(json));
        //		}
        //		System.out.println(DateUtils.longToStr(1416217220228l, FmtStr.yyyyMMdd_HHmmss));
        //		Protocol pl = new Protocol();
        //		pl.setBeanId("beanId");
        //		pl.setReqFlag("reqFlag");
        //		pl.setRespType("XML");
        //		List list = new ArrayList();
        //		for (int i = 0; i < 10; i++) {
        //			list.add("list-" + i);
        //		}
        //		//pl.setParams("pList", list);
        //		pl.setParams("ddd", "value");
        //		Map map = new HashMap();
        //		map.put("key001", list);
        //		map.put("key002", list);
        //		//map.put("key002", "value-002");
        //		//map.put("key003", "value-003");
        //		pl.setParams(map);
        //		String xml = XMLMapParse.instance().buildSingleXML(pl);
        //		System.out.println(xml);
        //		Map<String, Object> headMap = new HashMap<String, Object>();
        //		Map<String, Object> bodyMap = new HashMap<String, Object>();
        //		XMLMapParse.instance().xmlGetData(xml, headMap, bodyMap);
        //		System.out.println(headMap);
    }
}
